package lol.clann.minecraft.springboot.plugin.core.config.jackson;

import relocate.com.fasterxml.jackson.databind.JsonDeserializer;
import relocate.com.fasterxml.jackson.databind.JsonSerializer;
import relocate.com.fasterxml.jackson.databind.ObjectMapper;
import relocate.com.fasterxml.jackson.databind.SerializationFeature;
import relocate.com.fasterxml.jackson.databind.module.SimpleModule;
import com.ruoshui.utils.json.JsonUtils;
import lol.clann.minecraft.springboot.api.spi.jackson.JacksonDeserializer;
import lol.clann.minecraft.springboot.api.spi.jackson.JacksonSerializer;
import lol.clann.minecraft.springboot.plugin.core.config.jackson.fill.ThreadlocalSimpleValueInstantiators;

import javax.annotation.Nonnull;
import java.util.ServiceLoader;

/**
 * @author pyz
 * @date 2018/10/11 下午11:25
 */
public class Jackson {
    private static final ThreadLocal tl = new ThreadLocal();
    private static final ObjectMapper OBJECT_MAPPER = JsonUtils.getObjectMapper();

    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }

    static {
        // Date序列化为时间戳
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, true);

        setupThreadlocal();
        for (JacksonSerializer jacksonSerializer : ServiceLoader.load(JacksonSerializer.class)) {
            addSerializer(jacksonSerializer.getType(), (JsonSerializer) jacksonSerializer);
        }

        for (JacksonDeserializer jacksonDeserializer : ServiceLoader.load(JacksonDeserializer.class)) {
            addDeserializer(jacksonDeserializer.getType(), (JsonDeserializer) jacksonDeserializer);
        }
    }

    /**
     * 被@Inject注解的字段不序列化
     */
    private void setupIgnoreInject() {
        OBJECT_MAPPER.setAnnotationIntrospector(new AnnotationFilter());
    }

    /**
     * 正常反序列化,是jackson自己创建对象
     * 这里改造一下,
     * 如果Threadlocal中有对象,直接使用Threadlocal中的,不再创建,从而实现fill操作
     */
    private static void setupThreadlocal() {
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.setValueInstantiators(new ThreadlocalSimpleValueInstantiators());
        OBJECT_MAPPER.registerModule(simpleModule);
    }

    public static <T> void addSerializer(Class<T> type, JsonSerializer<T> serializer) {
        OBJECT_MAPPER.registerModule(new SimpleModule().addSerializer(type, serializer));
    }

    public static <T> void addDeserializer(Class<T> type, JsonDeserializer<T> deserializer) {
        OBJECT_MAPPER.registerModule(new SimpleModule().addDeserializer(type, deserializer));
    }

    public static void setTarget(@Nonnull Object o) {
        tl.set(o);
    }

    public static void clearTarget() {
        tl.remove();
    }

    public static Object getTarget(boolean clear) {
        Object o = tl.get();
        if (clear) {
            tl.remove();
        }
        return o;
    }

}
